#include "TrSession.h"
#include <QtCore/QDebug>

using namespace Market;

static QMap<QString, QMap<TrPeriod, QVector<QString>>> gs_TimeNodeSessionTemplate;

static QMap<QString, QMap<TrPeriod, QVector<QString>>> initializeSessionTemplate() {
    QMap<QString, QMap<TrPeriod, QVector<QString>>> templateMap;
    //============================================================================================
    //
    //============================================================================================
    templateMap["FN2300"] = {
        {M1,    Market::TrSession::TimeNode(M1,     {{2100, 2300}, {900, 1015}, {1030, 1130}, {1330, 1500}})}, 
        {M3,    Market::TrSession::TimeNode(M3,     {{2100, 2300}, {900, 1015}, {1030, 1130}, {1330, 1500}})},
        {M5,    Market::TrSession::TimeNode(M5,     {{2100, 2300}, {900, 1015}, {1030, 1130}, {1330, 1500}})},
        {M10,   Market::TrSession::TimeNode(M10,    {{2100, 2300}, {900, 1010}, {1025, 1130}, {1325, 1455}, {1450, 1500}})},
        {M15,   Market::TrSession::TimeNode(M15,    {{2100, 2300}, {900, 1015}, {1030, 1130}, {1330, 1500}})},
        {M30,   Market::TrSession::TimeNode(M30,    {{2100, 2300}, {900, 1015}, {1015, 1130}, {1315, 1445}, {1430, 1500}})},
        {H1,    {{QString("2200")},{QString("2300")},{QString("1000")},{QString("1115")},{QString("1415")},{QString("1500")}}},
        {H2,    {{QString("2300")},{QString("1115")},{QString("1500")}}}
    };
    //============================================================================================
    //
    //============================================================================================
    templateMap["FN0100"] = {
        {M1,    Market::TrSession::TimeNode(M1,     {{2100, 100}, {900, 1015}, {1030, 1130}, {1330, 1500}})}, 
        {M3,    Market::TrSession::TimeNode(M3,     {{2100, 100}, {900, 1015}, {1030, 1130}, {1330, 1500}})},
        {M5,    Market::TrSession::TimeNode(M5,     {{2100, 100}, {900, 1015}, {1030, 1130}, {1330, 1500}})},
        {M10,   Market::TrSession::TimeNode(M10,    {{2100, 100}, {900, 1010}, {1025, 1130}, {1325, 1455}, {1450, 1500}})},
        {M15,   Market::TrSession::TimeNode(M15,    {{2100, 100}, {900, 1015}, {1030, 1130}, {1330, 1500}})},
        {M30,   Market::TrSession::TimeNode(M30,    {{2100, 100}, {900, 1015}, {1015, 1130}, {1315, 1445}, {1430, 1500}})},
        {H1,    {{QString("2200")},{QString("2300")},{QString("0000")},{QString("0100")},{QString("1000")},{QString("1115")},{QString("1415")},{QString("1500")}}},
        {H2,    {{QString("2300")},{QString("1115")},{QString("1500")}}}
    };
    //============================================================================================
    // 黄金白银
    //============================================================================================
    templateMap["FN0230"] = {
        {M1,    Market::TrSession::TimeNode(M1,     {{2100, 230}, {900, 1015}, {1030, 1130}, {1330, 1500}})}, 
        {M3,    Market::TrSession::TimeNode(M3,     {{2100, 230}, {900, 1015}, {1030, 1130}, {1330, 1500}})},
        {M5,    Market::TrSession::TimeNode(M5,     {{2100, 230}, {900, 1015}, {1030, 1130}, {1330, 1500}})},
        {M10,   Market::TrSession::TimeNode(M10,    {{2100, 230}, {900, 1010}, {1025, 1130}, {1325, 1455}, {1450, 1500}})},
        {M15,   Market::TrSession::TimeNode(M15,    {{2100, 230}, {900, 1015}, {1030, 1130}, {1330, 1500}})},
        {M30,   Market::TrSession::TimeNode(M30,    {{2100, 230}, {900, 1015}, {1015, 1130}, {1315, 1445}, {1430, 1500}})},
        {H1,    {{QString("2200")},{QString("2300")},{QString("0000")},{QString("0100")},{QString("0200")},{QString("0930")},{QString("1045")},{QString("1345")},{QString("1445")},{QString("1500")}}},
        {H2,    {{QString("2300")},{QString("0100")},{QString("0930")},{QString("1345")},{QString("1500")}}}
    };
    //============================================================================================
    // 期货日盘 无夜盘
    //============================================================================================
    templateMap["FD0900"] = {
        {M1,    Market::TrSession::TimeNode(M1,     {{900, 1015}, {1030, 1130}, {1330, 1500}})}, 
        {M3,    Market::TrSession::TimeNode(M3,     {{900, 1015}, {1030, 1130}, {1330, 1500}})}, 
        {M5,    Market::TrSession::TimeNode(M5,     {{900, 1015}, {1030, 1130}, {1330, 1500}})}, 
        {M10,   Market::TrSession::TimeNode(M10,    {{900, 1010}, {1025, 1130}, {1325, 1455}, {1450, 1500}})},
        {M15,   Market::TrSession::TimeNode(M15,    {{900, 1015}, {1030, 1130}, {1330, 1500}})}, 
        {M30,   Market::TrSession::TimeNode(M30,    {{900, 1015}, {1015, 1130}, {1315, 1445}, {1430, 1500}})},
        {H1,    {{QString("1000")},{QString("1115")},{QString("1415")},{QString("1500")}}},
        {H2,    {{QString("1115")},{QString("1500")}}}
    };
    //============================================================================================
    // 债券类日盘交易时间
    //============================================================================================
    templateMap["FD1515"] = {
        {M1,    Market::TrSession::TimeNode(M1,     {{930, 1130}, {1300, 1515}})}, 
        {M3,    Market::TrSession::TimeNode(M3,     {{930, 1130}, {1300, 1515}})}, 
        {M5,    Market::TrSession::TimeNode(M5,     {{930, 1130}, {1300, 1515}})}, 
        {M10,   Market::TrSession::TimeNode(M10,    {{930, 1130}, {1300, 1515}, {1505, 1515}})}, 
        {M15,   Market::TrSession::TimeNode(M15,    {{930, 1130}, {1300, 1515}})}, 
        {M30,   Market::TrSession::TimeNode(M30,    {{930, 1130}, {1300, 1515}, {1445, 1515}})}, 
        {H1,    {{QString("1030")},{QString("1130")},{QString("1400")},{QString("1500")},{QString("1515")}}},
        {H2,    {{QString("1300")},{QString("1500")},{QString("1515")}}}
    };
    //============================================================================================
    // 股票类日盘 0930
    //============================================================================================
    templateMap["SD0930"] = {
        {M1,    Market::TrSession::TimeNode(M1,     {{930, 1130}, {1300, 1500}})}, 
        {M3,    Market::TrSession::TimeNode(M3,     {{930, 1130}, {1300, 1500}})}, 
        {M5,    Market::TrSession::TimeNode(M5,     {{930, 1130}, {1300, 1500}})}, 
        {M10,   Market::TrSession::TimeNode(M10,    {{930, 1130}, {1300, 1500}})}, 
        {M15,   Market::TrSession::TimeNode(M15,    {{930, 1130}, {1300, 1500}})}, 
        {M30,   Market::TrSession::TimeNode(M30,    {{930, 1130}, {1300, 1500}})},
        {H1,    {{QString("1030")},{QString("1130")},{QString("1400")},{QString("1500")}}},
        {H2,    {{QString("1300")},{QString("1500")}}}
    };
    return templateMap;
}

Market::TrSession::TrSession() {
    gs_TimeNodeSessionTemplate = initializeSessionTemplate();
    
    // 初始化交易时段
    m_tradingRanges["FN2300"] = {{2100, 2300}, {900, 1015}, {1030, 1130}, {1330, 1500}};
    m_tradingRanges["FN0100"] = {{2100, 100}, {900, 1015}, {1030, 1130}, {1330, 1500}};
    m_tradingRanges["FN0230"] = {{2100, 230}, {900, 1015}, {1030, 1130}, {1330, 1500}};
    m_tradingRanges["FD0900"] = {{900, 1015}, {1030, 1130}, {1330, 1500}};
    m_tradingRanges["FD1515"] = {{930, 1130}, {1300, 1515}};
    m_tradingRanges["SD0930"] = {{930, 1130}, {1300, 1500}};
}

QVector<QString> Market::TrSession::TimeNode(TrPeriod period, const std::vector<TimeRange>& range) {
    QVector<QString> nodes;
    for(const auto& pair: range) {
        uint32_t currentTime = pair.start;
        uint32_t endTime = pair.end; 
        // 如果结束时间比开始时间小，表示跨天
        bool crossesMidnight = endTime < currentTime;
        if (crossesMidnight) {
            endTime += 2400;  // 跨天处理：将结束时间增加24小时
        }
        while (currentTime <= endTime) {
            // 检查分钟是否超过60
            currentTime = currentTime % 100 >= 60 ? (currentTime / 100 + 1) * 100 + (currentTime % 100 - 60) : currentTime;
            if (currentTime != pair.start) {
                uint32_t displayTime = currentTime % 2400; // 把跨天的时间格式化回到0-2359
                nodes.push_back(QString::asprintf("%04d", displayTime));
            } 
            currentTime += period;
        }
    }
    return nodes;
}

QVector<QString> Market::TrSession::Get(const QString &name, TrPeriod period) {
    if (gs_TimeNodeSessionTemplate.contains(name) && gs_TimeNodeSessionTemplate[name].contains(period)) {
        return gs_TimeNodeSessionTemplate[name][period];
    }
    return QVector<QString>();
}

bool Market::TrSession::isInTradingTime(const QString& name, qint64 timestamp) const {
    QDateTime dt = QDateTime::fromSecsSinceEpoch(timestamp);
    return isInTradingTime(name, dt.time());
}

bool Market::TrSession::isInTradingTime(const QString& name, const QTime& time) const {
    if (!m_tradingRanges.contains(name)) {
        return false;
    }

    uint32_t timeNum = timeToNumber(time);
    const auto& ranges = m_tradingRanges[name];
    
    for (const auto& range : ranges) {
        if (isTimeInRange(timeNum, range)) {
            return true;
        }
    }
    
    return false;
}

QDateTime Market::TrSession::getBarStartTime(const QString& name, TrPeriod period, const QDateTime& time) const {
    if (!isInTradingTime(name, time.time())) {
        return QDateTime();
    }

    auto timePoints = Get(name, period);
    if (timePoints.isEmpty()) {
        return QDateTime();
    }

    uint32_t timeNum = timeToNumber(time.time());
    QDate date = time.date();

    // 如果是夜盘时段且时间小于6点，使用前一天的日期
    if (timeNum < 600) {
        date = date.addDays(-1);
    }

    for (int i = 0; i < timePoints.size(); ++i) {
        uint32_t pointTime = timePoints[i].toUInt();
        if (timeNum < pointTime) {
            if (i > 0) {
                return QDateTime(date, numberToTime(timePoints[i-1].toUInt()));
            }
            break;
        }
    }

    return QDateTime();
}

QDateTime Market::TrSession::getNextBarTime(const QString& name, TrPeriod period, const QDateTime& time) const {
    auto timePoints = Get(name, period);
    if (timePoints.isEmpty()) {
        return QDateTime();
    }

    uint32_t timeNum = timeToNumber(time.time());
    QDate date = time.date();

    for (const auto& point : timePoints) {
        uint32_t pointTime = point.toUInt();
        if (timeNum < pointTime) {
            // 如果下一个时间点跨天了（比如从2300到0000），需要调整日期
            if (pointTime < timeNum) {
                date = date.addDays(1);
            }
            return QDateTime(date, numberToTime(pointTime));
        }
    }

    // 如果没有找到下一个时间点，返回下一个交易日的第一个时间点
    return QDateTime(date.addDays(1), numberToTime(timePoints.first().toUInt()));
}

std::vector<TimeRange> Market::TrSession::getTradingRanges(const QString& name) const {
    if (m_tradingRanges.contains(name)) {
        return m_tradingRanges[name];
    }
    return std::vector<TimeRange>();
}

uint32_t Market::TrSession::timeToNumber(const QTime& time) {
    return time.hour() * 100 + time.minute();
}

QTime Market::TrSession::numberToTime(uint32_t timeNum) {
    return QTime(timeNum / 100, timeNum % 100);
}

bool Market::TrSession::isCrossDay(uint32_t startTime, uint32_t endTime) {
    return endTime < startTime;
}

bool Market::TrSession::isTimeInRange(uint32_t timeNum, const TimeRange& range) const {
    if (isCrossDay(range.start, range.end)) {
        return timeNum >= range.start || timeNum <= range.end;
    }
    return timeNum >= range.start && timeNum <= range.end;
}

uint32_t Market::TrSession::normalizeTimeNumber(uint32_t timeNum) const {
    return timeNum % 2400;
}